package com.zg.scf.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zg.common.core.dao.auth.AuthRole;
import com.zg.common.core.dao.auth.AuthRoleDao;
import com.zg.common.core.dao.auth.AuthRoleUser;
import com.zg.common.core.dao.auth.AuthRoleUserDao;
import com.zg.common.core.dao.scf.CompanyDao;
import com.zg.common.core.dao.scf.EnLevelDao;
import com.zg.common.core.dao.scf.ScfRoleExtDao;
import com.zg.common.core.dao.scf.entity.Company;
import com.zg.common.core.dao.scf.entity.EnLevel;
import com.zg.common.core.dao.scf.entity.ScfRoleExt;
import com.zg.common.core.exception.BusinessException;
import com.zg.common.web.Req;
import com.zg.scf.enm.CompanyInfoConstants;
import com.zg.scf.enm.UserTypeEnum;
import com.zg.scf.domain.req.ScfRoleAddReq;
import com.zg.scf.domain.req.ScfRoleEditReq;
import com.zg.scf.domain.req.ScfRoleListReq;
import com.zg.scf.domain.req.ScfRolePageReq;
import com.zg.scf.domain.vo.ScfRoleVo;
import com.zg.scf.service.ScfRoleService;
import com.zg.scf.util.DataScopeUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ScfRoleServiceImpl implements ScfRoleService {

    private final AuthRoleDao authRoleDao;
    private final ScfRoleExtDao scfRoleExtDao;
    private final DataScopeUtil dataScopeUtil;
    private final CompanyDao companyDao;
    private final AuthRoleUserDao authRoleUserDao;
    private final EnLevelDao enLevelDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(ScfRoleAddReq req) {
        String currUserType = Req.getCurrUser().getType();
        Long companyId = req.getCompanyId();
        boolean isSystemUser = UserTypeEnum.SYSTEM.getCode().equals(currUserType);
        if (isSystemUser) {
            if (companyId != null) {
                Company company = companyDao.getById(companyId);
                if (company == null) {
                    BusinessException.happen("请选择正确所属企业");
                }
                req.setType(null);
                req.setAuthStatus(null);
                req.setEnLevelId(null);
            } else {
                String type = req.getType();
                if (StrUtil.isBlank(type)) {
                    BusinessException.happen("请选择正确的类型");
                }
                UserTypeEnum userTypeEnum = UserTypeEnum.getByCode(type);
                if (userTypeEnum == null) {
                    BusinessException.happen("请选择正确的类型");
                }
                if (!UserTypeEnum.SYSTEM.getCode().equals(type)) {
                    String authStatus = req.getAuthStatus();
                    if (StrUtil.isBlank(authStatus)) {
                        BusinessException.happen("请选择正确的认证状态");
                    }
                    if (CompanyInfoConstants.AuthStatusEnum.YES_STATUS.getValue().equals(type) && req.getEnLevelId() == null) {
                        BusinessException.happen("请选择正确的企业等级");
                    } else if (CompanyInfoConstants.AuthStatusEnum.NOT_STATUS.getValue().equals(type)) {
                        req.setEnLevelId(null);
                    }
                } else {
                    req.setAuthStatus(null);
                    req.setEnLevelId(null);
                }
            }
        } else {
            Long orgDataScope = dataScopeUtil.getOrgDataScope();
            if (companyId == null || !companyId.equals(orgDataScope)) {
                BusinessException.happen("请选择正确所属企业");
            }
            req.setType(null);
            req.setAuthStatus(null);
            req.setEnLevelId(null);
        }

        List<AuthRole> nameList = authRoleDao.list(
                new LambdaQueryWrapper<AuthRole>()
                        .eq(AuthRole::getName, req.getName())
        );
        if (!nameList.isEmpty()) {
            Set<Long> roleIds = nameList.stream().map(AuthRole::getId).collect(Collectors.toSet());
            boolean exists = scfRoleExtDao.exists(
                    new LambdaQueryWrapper<ScfRoleExt>()
                            .in(ScfRoleExt::getRoleId, roleIds)
                            .eq(req.getCompanyId() != null, ScfRoleExt::getCompanyId, req.getCompanyId())
                            .isNull(req.getCompanyId() == null, ScfRoleExt::getCompanyId)
            );
            if (exists) {
                BusinessException.happen("角色名称已存在");
            }
        }

        AuthRole authRole = new AuthRole();
        authRole.setName(req.getName());
        authRole.setIntro(req.getIntro());
        authRole.setSearchStr(authRole.getName() + authRole.getIntro());
        authRoleDao.save(authRole);
        ScfRoleExt scfRoleExt = BeanUtil.copyProperties(req, ScfRoleExt.class);
        scfRoleExt.setRoleId(authRole.getId());
        scfRoleExtDao.save(scfRoleExt);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(ScfRoleEditReq req) {
        AuthRole authRole = authRoleDao.getById(req.getRoleId());
        if (authRole == null) {
            BusinessException.happen("请选择正确的角色");
        }
        List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                new LambdaQueryWrapper<ScfRoleExt>()
                        .eq(ScfRoleExt::getRoleId, req.getRoleId())
        );
        if (scfRoleExtList.size() != 1) {
            BusinessException.happen("角色配置错误，请联系管理员");
        }
        ScfRoleExt scfRoleExt = scfRoleExtList.get(0);

        String currUserType = Req.getCurrUser().getType();
        Long companyId = req.getCompanyId();
        boolean isSystemUser = UserTypeEnum.SYSTEM.getCode().equals(currUserType);
        if (isSystemUser) {
            if (companyId != null) {
                Company company = companyDao.getById(companyId);
                if (company == null) {
                    BusinessException.happen("请选择正确所属企业");
                }
                req.setType(null);
                req.setAuthStatus(null);
                req.setEnLevelId(null);
            } else {
                String type = req.getType();
                if (StrUtil.isBlank(type)) {
                    BusinessException.happen("请选择正确的类型");
                }
                UserTypeEnum userTypeEnum = UserTypeEnum.getByCode(type);
                if (userTypeEnum == null) {
                    BusinessException.happen("请选择正确的类型");
                }
                if (!UserTypeEnum.SYSTEM.getCode().equals(type)) {
                    String authStatus = req.getAuthStatus();
                    if (StrUtil.isBlank(authStatus)) {
                        BusinessException.happen("请选择正确的认证状态");
                    }
                    if (CompanyInfoConstants.AuthStatusEnum.YES_STATUS.getValue().equals(type) && req.getEnLevelId() == null) {
                        BusinessException.happen("请选择正确的企业等级");
                    } else if (CompanyInfoConstants.AuthStatusEnum.NOT_STATUS.getValue().equals(type)) {
                        req.setEnLevelId(null);
                    }
                } else {
                    req.setAuthStatus(null);
                    req.setEnLevelId(null);
                }
            }
        } else {
            Long orgDataScope = dataScopeUtil.getOrgDataScope();
            if (companyId == null || !companyId.equals(orgDataScope)) {
                BusinessException.happen("请选择正确所属企业");
            }
            req.setType(null);
            req.setAuthStatus(null);
            req.setEnLevelId(null);
        }

        if (!req.getName().equals(authRole.getName())) {
            List<AuthRole> nameList = authRoleDao.list(
                    new LambdaQueryWrapper<AuthRole>()
                            .eq(AuthRole::getName, req.getName())
            );
            if (!nameList.isEmpty()) {
                Set<Long> roleIds = nameList.stream().map(AuthRole::getId).collect(Collectors.toSet());
                boolean exists = scfRoleExtDao.exists(
                        new LambdaQueryWrapper<ScfRoleExt>()
                                .in(ScfRoleExt::getRoleId, roleIds)
                                .eq(req.getCompanyId() != null, ScfRoleExt::getCompanyId, req.getCompanyId())
                                .isNull(req.getCompanyId() == null, ScfRoleExt::getCompanyId)
                );
                if (exists) {
                    BusinessException.happen("角色名称已存在");
                }
            }
        }

        authRole.setName(req.getName());
        authRole.setIntro(req.getIntro());
        authRole.setSearchStr(authRole.getName() + authRole.getIntro());
        authRoleDao.updateById(authRole);
        BeanUtil.copyProperties(req, scfRoleExt);
        scfRoleExtDao.updateById(scfRoleExt);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(List<Long> idList) {
        List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                new LambdaQueryWrapper<ScfRoleExt>()
                        .in(ScfRoleExt::getRoleId, idList)
        );

        String currUserType = Req.getCurrUser().getType();
        boolean isSystemUser = UserTypeEnum.SYSTEM.getCode().equals(currUserType);
        Long orgDataScope = dataScopeUtil.getOrgDataScope();
        if (!isSystemUser) {
            for (ScfRoleExt scfRoleExt : scfRoleExtList) {
                if (!orgDataScope.equals(scfRoleExt.getCompanyId())) {
                    BusinessException.happen("该数据没有操作权限");
                    break;
                }
            }
        }
        authRoleDao.removeBatchByIds(idList);
        scfRoleExtDao.remove(new LambdaQueryWrapper<ScfRoleExt>()
                .in(ScfRoleExt::getRoleId, idList));
        authRoleUserDao.remove(new LambdaQueryWrapper<AuthRoleUser>()
                .in(AuthRoleUser::getRoleId, idList));
    }

    @Override
    public IPage<ScfRoleVo> pageSystem(ScfRolePageReq req) {
        IPage<ScfRoleVo> result = new Page<>(req.getPage(), req.getPageSize());
        Map<Long, List<ScfRoleVo>> enLevelMap = new HashMap<>();
        Map<Long, List<ScfRoleVo>> companyMap = new HashMap<>();
        String currUserType = Req.getCurrUser().getType();
        boolean isSystemUser = UserTypeEnum.SYSTEM.getCode().equals(currUserType);
        if (!isSystemUser) {
            return result;
        }
        List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                new LambdaQueryWrapper<ScfRoleExt>()
                        .isNotNull(ScfRoleExt::getType)
        );
        if (scfRoleExtList.isEmpty()) {
            return result;
        }
        Map<Long, ScfRoleExt> scfRoleExtMap = scfRoleExtList.stream()
                .collect(Collectors.toMap(ScfRoleExt::getRoleId, Function.identity()));

        IPage<AuthRole> page = authRoleDao.page(
                new Page<>(req.getPage(), req.getPageSize()),
                new LambdaQueryWrapper<AuthRole>()
                        .in(AuthRole::getId, scfRoleExtMap.keySet())
                        .like(StrUtil.isNotBlank(req.getRoleName()),
                                AuthRole::getName,"%" + req.getRoleName() + "%")
        );
        if (page.getRecords().isEmpty()) {
            return result;
        }
        result = BeanUtil.toBean(page, Page.class);
        result.setRecords(BeanUtil.copyToList(page.getRecords(), ScfRoleVo.class));
        for (ScfRoleVo record : result.getRecords()) {
            Long roleId = record.getId();
            ScfRoleExt scfRoleExt = scfRoleExtMap.get(roleId);
            record.setRoleId(scfRoleExt.getRoleId());
            record.setType(scfRoleExt.getType());
            record.setAuthStatue(scfRoleExt.getAuthStatus());
            Long enLevelId = scfRoleExt.getEnLevelId();
            if (enLevelId != null) {
                enLevelMap.computeIfAbsent(enLevelId, v -> new ArrayList<>()).add(record);
            }
            Long companyId = scfRoleExt.getCompanyId();
            if (companyId != null) {
                companyMap.computeIfAbsent(companyId, v -> new ArrayList<>()).add(record);
            }
        }

        if (!enLevelMap.isEmpty()) {
            List<EnLevel> enLevelList = enLevelDao.listByIds(enLevelMap.keySet());
            for (EnLevel enLevel : enLevelList) {
                List<ScfRoleVo> list = enLevelMap.get(enLevel.getId());
                for (ScfRoleVo scfRoleVo : list) {
                    scfRoleVo.setEnLevel(enLevel);
                }
            }
        }
        if (!companyMap.isEmpty()) {
            List<Company> companyList = companyDao.listByIds(companyMap.keySet());
            for (Company company : companyList) {
                List<ScfRoleVo> list = companyMap.get(company.getId());
                for (ScfRoleVo scfRoleVo : list) {
                    scfRoleVo.setCompany(company);
                }
            }
        }
        return result;
    }

    @Override
    public IPage<ScfRoleVo> pageCompany(ScfRolePageReq req) {
        IPage<ScfRoleVo> result = new Page<>(req.getPage(), req.getPageSize());
        Map<Long, List<ScfRoleVo>> companyMap = new HashMap<>();

        Long orgDataScope = dataScopeUtil.getOrgDataScope();
        List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                new LambdaQueryWrapper<ScfRoleExt>()
                        .isNull(ScfRoleExt::getType)
                        .isNotNull(ScfRoleExt::getCompanyId)
                        .eq(orgDataScope != null, ScfRoleExt::getCompanyId, orgDataScope)
        );
        if (scfRoleExtList.isEmpty()) {
            return result;
        }
        Map<Long, ScfRoleExt> scfRoleExtMap = scfRoleExtList.stream()
                .collect(Collectors.toMap(ScfRoleExt::getRoleId, Function.identity()));

        IPage<AuthRole> page = authRoleDao.page(
                new Page<>(req.getPage(), req.getPageSize()),
                new LambdaQueryWrapper<AuthRole>()
                        .in(AuthRole::getId, scfRoleExtMap.keySet())
                        .like(StrUtil.isNotBlank(req.getRoleName()),
                                AuthRole::getName,"%" + req.getRoleName() + "%")
        );
        if (page.getRecords().isEmpty()) {
            return result;
        }
        result = BeanUtil.toBean(page, Page.class);
        result.setRecords(BeanUtil.copyToList(page.getRecords(), ScfRoleVo.class));
        for (ScfRoleVo record : result.getRecords()) {
            Long roleId = record.getId();
            ScfRoleExt scfRoleExt = scfRoleExtMap.get(roleId);
            record.setRoleId(scfRoleExt.getRoleId());
            Long companyId = scfRoleExt.getCompanyId();
            if (companyId != null) {
                companyMap.computeIfAbsent(companyId, v -> new ArrayList<>()).add(record);
            }
        }

        if (!companyMap.isEmpty()) {
            List<Company> companyList = companyDao.listByIds(companyMap.keySet());
            for (Company company : companyList) {
                List<ScfRoleVo> list = companyMap.get(company.getId());
                for (ScfRoleVo scfRoleVo : list) {
                    scfRoleVo.setCompany(company);
                }
            }
        }
        return result;
    }

    @Override
    public List<ScfRoleVo> list(ScfRoleListReq req) {
        List<ScfRoleVo> result = new ArrayList<>();
        Map<Long, List<ScfRoleVo>> enLevelMap = new HashMap<>();
        Map<Long, List<ScfRoleVo>> companyMap = new HashMap<>();
        String currUserType = Req.getCurrUser().getType();
        boolean isSystemUser = UserTypeEnum.SYSTEM.getCode().equals(currUserType);
        if (isSystemUser) {
            Map<Long, ScfRoleExt> scfRoleExtMap = new HashMap<>();
            Long companyId = req.getCompanyId();
            if (companyId != null) {
                List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                        new LambdaQueryWrapper<ScfRoleExt>()
                                .eq(ScfRoleExt::getCompanyId, companyId)
                                .eq(StrUtil.isNotBlank(req.getType()), ScfRoleExt::getType, req.getType())
                );
                if (scfRoleExtList.isEmpty()) {
                    return new ArrayList<>();
                }
                scfRoleExtMap = scfRoleExtList.stream()
                        .collect(Collectors.toMap(ScfRoleExt::getRoleId, Function.identity()));
            }
            List<AuthRole> list = authRoleDao.list(
                    new LambdaQueryWrapper<AuthRole>()
                            .in(!scfRoleExtMap.isEmpty(), AuthRole::getId, scfRoleExtMap.keySet())
                            .like(StrUtil.isNotBlank(req.getRoleName()),AuthRole::getName,"%"+req.getRoleName()+"%")
            );
            BeanUtil.copyProperties(list, result);

            if (!scfRoleExtMap.isEmpty()) {
                for (ScfRoleVo scfRoleVo : result) {
                    ScfRoleExt scfRoleExt = scfRoleExtMap.get(scfRoleVo.getId());
                    scfRoleVo.setRoleId(scfRoleExt.getRoleId());
                    scfRoleVo.setType(scfRoleExt.getType());
                    scfRoleVo.setAuthStatue(scfRoleExt.getAuthStatus());
                    Long enLevelId = scfRoleExt.getEnLevelId();
                    if (enLevelId != null) {
                        enLevelMap.computeIfAbsent(enLevelId, v -> new ArrayList<>()).add(scfRoleVo);
                    }
                    Long company = scfRoleExt.getCompanyId();
                    if (company != null) {
                        companyMap.computeIfAbsent(company, v -> new ArrayList<>()).add(scfRoleVo);
                    }
                }
            } else {
                Map<Long, ScfRoleVo> scfRoleMap = result.stream()
                        .collect(Collectors.toMap(ScfRoleVo::getId, Function.identity()));
                List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                        new LambdaQueryWrapper<ScfRoleExt>()
                                .in(ScfRoleExt::getRoleId, scfRoleMap.keySet())
                );
                for (ScfRoleExt scfRoleExt : scfRoleExtList) {
                    Long roleId = scfRoleExt.getRoleId();
                    ScfRoleVo scfRoleVo = scfRoleMap.get(roleId);
                    scfRoleVo.setRoleId(roleId);
                    scfRoleVo.setType(scfRoleExt.getType());
                    scfRoleVo.setAuthStatue(scfRoleExt.getAuthStatus());
                    Long enLevelId = scfRoleExt.getEnLevelId();
                    if (enLevelId != null) {
                        enLevelMap.computeIfAbsent(enLevelId, v -> new ArrayList<>()).add(scfRoleVo);
                    }
                    Long company = scfRoleExt.getCompanyId();
                    if (company != null) {
                        companyMap.computeIfAbsent(company, v -> new ArrayList<>()).add(scfRoleVo);
                    }
                }
            }
        } else {
            List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                    new LambdaQueryWrapper<ScfRoleExt>()
                            .eq(ScfRoleExt::getType, currUserType)
                            .eq(ScfRoleExt::getCompanyId, dataScopeUtil.getOrgDataScope())
            );
            if (scfRoleExtList.isEmpty()) {
                return new ArrayList<>();
            }
            Map<Long, ScfRoleExt> scfRoleExtMap = scfRoleExtList.stream()
                    .collect(Collectors.toMap(ScfRoleExt::getRoleId, Function.identity()));

            List<AuthRole> list = authRoleDao.list(
                    new LambdaQueryWrapper<AuthRole>()
                            .in(AuthRole::getId, scfRoleExtMap.keySet())
                            .like(StrUtil.isNotBlank(req.getRoleName()),
                                    AuthRole::getName,"%" + req.getRoleName() + "%")
            );
            BeanUtil.copyProperties(list, result);
            for (ScfRoleVo scfRoleVo : result) {
                ScfRoleExt scfRoleExt = scfRoleExtMap.get(scfRoleVo.getRoleId());
                scfRoleVo.setRoleId(scfRoleExt.getRoleId());
                scfRoleVo.setType(scfRoleExt.getType());
                scfRoleVo.setAuthStatue(scfRoleExt.getAuthStatus());
                Long enLevelId = scfRoleExt.getEnLevelId();
                if (enLevelId != null) {
                    enLevelMap.computeIfAbsent(enLevelId, v -> new ArrayList<>()).add(scfRoleVo);
                }
                Long companyId = scfRoleExt.getCompanyId();
                if (companyId != null) {
                    companyMap.computeIfAbsent(companyId, v -> new ArrayList<>()).add(scfRoleVo);
                }
            }
        }

        if (!enLevelMap.isEmpty()) {
            List<EnLevel> enLevelList = enLevelDao.listByIds(enLevelMap.keySet());
            for (EnLevel enLevel : enLevelList) {
                List<ScfRoleVo> list = enLevelMap.get(enLevel.getId());
                for (ScfRoleVo scfRoleVo : list) {
                    scfRoleVo.setEnLevel(enLevel);
                }
            }
        }
        if (!companyMap.isEmpty()) {
            List<Company> companyList = companyDao.listByIds(companyMap.keySet());
            for (Company company : companyList) {
                List<ScfRoleVo> list = companyMap.get(company.getId());
                for (ScfRoleVo scfRoleVo : list) {
                    scfRoleVo.setCompany(company);
                }
            }
        }
        return result;
    }
}
